package cn.iocoder.yudao.module.infra.framework.security.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.module.infra.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.infra.enums.security.UriSecurityModeEnum;
import cn.iocoder.yudao.module.infra.framework.security.config.UriSecurityConfig;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.List;

@Slf4j
public class UriSecurityInterceptor implements HandlerInterceptor {
    private final UriSecurityConfig uriSecurityConfig;

    public UriSecurityInterceptor(UriSecurityConfig uriSecurityConfig) {
        this.uriSecurityConfig = uriSecurityConfig;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        final String uri = request.getRequestURI();

        final UriSecurityModeEnum uriSecurityMode = uriSecurityConfig.getSecurityMode();
        if (uriSecurityMode == null) {
            //log.warn("未开启uri安全模式, uri = {}", uri);
            return true;
        }

        switch (uriSecurityMode) {
            case URI_WHITE_LIST:
                final boolean inWhitelist = isInUriList(uri, uriSecurityConfig.getUriWhiteList());
                if (!inWhitelist) {
                    log.warn("uri不在白名单中, uri = {}", uri);
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.URI_NOT_IN_WHITE_LIST, uri);
                }
                break;
            case URI_BLACK_LIST:
                final boolean inBlacklist = isInUriList(uri, uriSecurityConfig.getUriBlackList());
                if (inBlacklist) {
                    log.warn("uri在黑名单中, uri = {}", uri);
                    throw ServiceExceptionUtil.exception(ErrorCodeConstants.URI_IN_BLACK_LIST, uri);
                }
                break;
            default:
                throw new IllegalArgumentException(String.format("未知的uriSecurityMode：%s", uriSecurityMode));
        }

        log.info("uri安全模式-通过, uri = {}", uri);
        return true;
    }

    private boolean isInUriList(String uri, List<String> uriList) {
        if (CollUtil.isNotEmpty(uriList)) {
            for (String configUri : uriList) {
                try {
                    final boolean match = ReUtil.isMatch(configUri, uri);
                    if (match) {
                        return true;
                    }
                } catch (Exception e) {
                    log.error(String.format("match url error, uri = %s, configUri = %s", uri, configUri), e);
                }
            }
        }
        return false;
    }

}
